extern crate dunce;
use std::{env, fs};
//use std::path::PathBuf;

fn main() -> miette::Result<()> {

    let external_dir = if let Ok(external_dir) = env::var("REST_EXT_DIR") {
        external_dir
    } else {"".to_string()};

    generate_libxc_names_and_values();

    let library_names = ["restmatr","openblas","xc","hdf5","rest2fch","gomp"];
    library_names.iter().for_each(|name| {
        println!("cargo:rustc-link-lib={}",*name);
    });

    // conditionally link to the libraries based on the features
    #[cfg(feature = "dftd3")]
    println!("cargo:rustc-link-lib=s-dftd3");
    #[cfg(feature = "dftd4")]
    println!("cargo:rustc-link-lib=dftd4");

    let library_path = [
        dunce::canonicalize(&external_dir).unwrap(),
    ];
    library_path.iter().for_each(|path| {
        println!("cargo:rustc-link-search={}",env::join_paths(&[path]).unwrap().to_str().unwrap())
    });

    Ok(())

}

fn generate_libxc_names_and_values() {
    // Retrieve the REST_HOME environment variable or use an empty string if not set
    let rest_dir = if let Ok(rest_dir) = env::var("REST_HOME") {
        rest_dir
    } else {"".to_string()};

    // Define the output directory and destination path for the generated libxc code
    let _out_dir = format!("{}/rest/src/dft/libxc", &rest_dir);
    let dest_path = format!("{}/rest/src/dft/libxc/names_and_values.rs", &rest_dir);
    let libxc_full_path = format!("{}/rest/src/dft/libxc/libxc_full.rs", &rest_dir);

    // if std::path::Path::new(&dest_path).exists() {
    //     println!("File {} already exists. Skipping libxc code generation.", dest_path);
    //     return;
    // }
    println!("Generating libxc code from {} to {}", libxc_full_path, dest_path);

    // Read the contents of libxc_full.rs and parse lines that start with "pub const"
    let constants_code = fs::read_to_string(libxc_full_path).unwrap();
    let const_lines: Vec<_> = constants_code
        .lines()
        .filter(|line| line.trim().starts_with("pub const"))
        .map(|line| {
            let parts: Vec<_> = line.split_whitespace().collect();
            let name = parts[2].trim_end_matches(':');
            (name, line)
        })
        .collect();

    // Generate the MAP code by filtering and formatting the parsed lines
    let generated_code = format!(
        "// This map of libxc names and values is auto-generated by reading libxc_full.rs\npub const MAP: &[(&str, usize)] = &[\n{}\n];",
        const_lines
            .iter()
            .filter(|(_, line)| line.contains("u32"))
            .map(|(name, line)| {
                let value: Vec<_> = line.split('=').collect();
                let value = value[1].trim().trim_end_matches(';');
                format!("    (\"{}\", {}),", name, value)
            })
            .collect::<Vec<_>>()
            .join("\n")
    );

    // Write the generated code to the destination path
    fs::write(&dest_path, generated_code).unwrap();
    println!("cargo:rerun-if-changed={}", dest_path);
}
